﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.Practices.ServiceLocation;
using CodeSaude.Domain.Interfaces.Repository;
using CodeSaude.Infrastructure.Data.Context;
using CodeSaude.Infrastructure.Data.Interfaces;

namespace CodeSaude.Infrastructure.Data.Repositories {
    public class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : class
    {
        private readonly ContextManager _contextManager = ServiceLocator.Current.GetInstance<IContextManager>() as ContextManager;
        protected IDbSet<TEntity> DbSet;
        protected readonly DbContext Context;

        protected CodeSaudeContext Db;

        public BaseRepository() {
            Context = _contextManager.GetContext();
            DbSet = Context.Set<TEntity>();
        }

        public virtual void Add(TEntity obj) {
            DbSet.Add(obj);
        }

        public virtual TEntity GetById(int id) {
            return DbSet.Find(id);
        }

        public virtual IEnumerable<TEntity> GetAll() {
            return DbSet.ToList();
        }

        public virtual IEnumerable<TEntity> GetAllReadOnly() {
            return DbSet.AsNoTracking();
        }

        public void SaveChanges()
        {
            throw new NotImplementedException();
        }

        public virtual IEnumerable<TEntity> FindReadOnly(Expression<Func<TEntity, bool>> predicate)
        {
            return DbSet.AsNoTracking().Where(predicate);
        }

        public virtual void Update(TEntity obj) {
            var entry = Context.Entry(obj);
            DbSet.Attach(obj);
            entry.State = EntityState.Modified;
        }

        public virtual void Remove(TEntity obj) {
            DbSet.Remove(obj);
        }

        public virtual IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate) {
            return DbSet.Where(predicate);
        }

        public void Dispose() {
            Context.Dispose();
            GC.SuppressFinalize(this);
        }

        public virtual IEnumerable<TEntity> FindNoProxy(Expression<Func<TEntity, bool>> where, string[] includes = null)
        {
            List<TEntity> list;
            using (Db = new CodeSaudeContext())
            {
                Db.Configuration.ProxyCreationEnabled = false;
                IQueryable<TEntity> qr = Db.Set<TEntity>();
                if (includes != null)
                {
                    for (var i = 0; i < includes.Count(); i++)
                    {
                        qr = qr.Include(includes[i]);
                    }
                }
                list = qr.Where(where).ToList();
            }
            return list;
        }

        public virtual List<TEntity> Get(Expression<Func<TEntity, bool>> predicate, string[] includes = null)
        {
            List<TEntity> list = null;
            using (Db = new CodeSaudeContext())
            {
                Db.Configuration.LazyLoadingEnabled = false;
                Db.Database.Log = s => Debug.WriteLine(s);
                IQueryable<TEntity> qr = Db.Set<TEntity>();
                if (includes != null)
                {
                    for (var i = 0; i < includes.Count(); i++)
                    {
                        qr = qr.Include(includes[i]);
                    }
                }
                list = qr.Where(predicate).AsNoTracking().ToList();
            }
            return list;
        }

        public IEnumerable<TEntity> GetAllNoProxy(string[] includes = null)
        {
            List<TEntity> list = null;
            using (Db = new CodeSaudeContext())
            {
                Db.Configuration.LazyLoadingEnabled = false;
                Db.Database.Log = s => Debug.WriteLine(s);
                IQueryable<TEntity> qr = Db.Set<TEntity>();
                if (includes != null)
                {
                    for (var i = 0; i < includes.Count(); i++)
                    {
                        qr = qr.Include(includes[i]);
                    }
                }

                list = qr.AsNoTracking().ToList();
            }
            return list;
        }
    }
}
